package com.haohuo.framework.mybatisplusgen;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.haohuo.framework.mybatisplusgen.compose.ComposeConfig;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;

// 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中

/**
 *
 */
public class CodeGenerator {

    protected static final Logger logger = LoggerFactory.getLogger(CodeGenerator.class);

    @Test
    public void test(){
        System.out.println(PropertyUtil.getProp("author"));
    }

    public static void main(String[] args) {
        /* _12302_2021/5/9_<
            清除刚才生成的文件，为了保护生成后修改的文件，做了简单的判断：
            如果输出目录跟上一次生成使用的是一样的。则执行删除操作。
            如果换输出目录了，则不予删除。
        > */
        //deleteGenerateFile();

        //生成文件
        generate();
    }

    public static void generate(){
        //全局变量
        String projectPath = PropertyUtil.getProp("output");
        projectPath = projectPath == null ?
                System.getProperty("user.dir") + "/src/main/java" : projectPath;
        String contains = PropertyUtil.getProp("contains");
        String author = PropertyUtil.getProp("author");

        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(projectPath);
        gc.setAuthor(author);
        gc.setOpen(false);
        gc.setFileOverride(true);

        /* _12302_2021/4/25_<项目中生成的时间为localDateTime,需要改为java.util.data.> */
        /* _12302_2021/4/25_<
        处理逻辑在com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder.getTablesInfo()
        之后方法 includeTableList.forEach(ti -> convertTableFields(ti, config));在此处会用到GlobalConfig中的DateType.
        > */
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(PropertyUtil.getProp("swagger2", Boolean.class));
        gc.setBaseResultMap(true);
        gc.setBaseColumnList(true);
        mpg.setGlobalConfig(gc);


        //配置自定义属性注入
        //自定义属性注入:abc
        //在.ftl(或者是.vm)模板中，通过${cfg.abc}获取属性
        mpg.setCfg(new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<>();
                GlobalConfig globalConfig = this.getConfig().getGlobalConfig();
                map.put("composeImport",mpg.getPackageInfo().getParent() + StringPool.DOT + PropertyUtil.getProp("composePkgName"));
                this.setMap(map);
                //this.setFileCreate((w,t,f) -> contains.contains("compose") ? true : false);
                ArrayList arrayList = new ArrayList();
                if(contains.contains("compose"))
                    arrayList.add(new ComposeConfig("templates/compose.java", globalConfig.getOutputDir(), mpg.getPackageInfo())) ;
                this.setFileOutConfigList(arrayList);
            }
        });

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl(PropertyUtil.getProp("url"));
        // dsc.setSchemaName("public");
        dsc.setDriverName(PropertyUtil.getProp("driver"));
        dsc.setUsername(PropertyUtil.getProp("username"));
        dsc.setPassword(PropertyUtil.decrypt(PropertyUtil.getProp("password")));
        dsc.setDbQuery(new MySqlQuery() {
            /**
             * 重写父类预留查询自定义字段<br>
             * 这里查询的 SQL 对应父类 tableFieldsSql 的查询字段，默认不能满足你的需求请重写它<br>
             * 模板中调用：  table.fields 获取所有字段信息，
             * 然后循环字段获取 field.customMap 从 MAP 中获取注入字段如下  NULL 或者 PRIVILEGES
             */
            @Override
            public String[] fieldCustom() {
                return new String[]{"NULL"};
            }
        });
        mpg.setDataSource(dsc);


        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(PropertyUtil.getProp("moduleName"));
        pc.setParent(PropertyUtil.getProp("companySuffix"));
        pc.setController(PropertyUtil.getProp("controllerPkgName"));
        pc.setEntity(PropertyUtil.getProp("entityPkgName"));
        pc.setMapper(PropertyUtil.getProp("mapperPkgName"));
        pc.setXml(PropertyUtil.getProp("xmlPkgName"));
        pc.setService(PropertyUtil.getProp("servicePkgName"));
        pc.setServiceImpl(PropertyUtil.getProp("implPkgName"));
        mpg.setPackageInfo(pc);


        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        new TemplateConfigBuilder(templateConfig,contains)
                .addLast(contain -> contain.contains("controller"), tc -> tc.setController("templates/controller.java"),tc->tc.setController(null))
                .addLast(contain -> contain.contains("entity"), tc -> tc.setEntity("templates/entity.java"),tc->tc.setEntity(null))
                .addLast(contain -> contain.contains("mapper"), tc -> tc.setMapper("templates/mapper.java"),tc->tc.setMapper(null))
                .addLast(contain -> contain.contains("xml"), tc -> tc.setXml("templates/mapper.xml"),tc->tc.setXml(null))
                .addLast(contain -> contain.contains("service"), tc -> tc.setService("templates/service.java"),tc->tc.setService(null))
                .addLast(contain -> contain.contains("impl"), tc -> tc.setServiceImpl("templates/serviceImpl.java"),tc->tc.setServiceImpl(null));
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);

        // 写于父类中的公共字段
        strategy.setSuperEntityColumns(PropertyUtil.getProp("superEntityColumns",String[].class));
        strategy.setEnableSqlFilter(!PropertyUtil.getProp("tables").contains(".*"));
        strategy.setInclude(PropertyUtil.getProp("tables").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(PropertyUtil.getProp("tablePrefix"));
        strategy.setChainModel(true);
        mpg.setStrategy(strategy);
        ExFreemarkerTemplateEngine templateEngine = new ExFreemarkerTemplateEngine();
        mpg.setTemplateEngine(templateEngine);
        mpg.execute();
        //templateEngine.serialization(System.getProperty("user.dir") + "/src/main/resources/serialization.object");
    }

    /**
     * 1,有待完善，可以序列化一个map,  key【output, current, files, 】
     * 2,递归删除空目录。
     */
    private static void deleteGenerateFile() {

        String file = System.getProperty("user.dir") + "/src/main/resources/serialization.object";
        String output = PropertyUtil.getProp("output");
        List<String> deserialization = ExFreemarkerTemplateEngine.deserialization(file);
        if(deserialization != null && !deserialization.get(0).equals(output)) return;
        deserialization.forEach((each) -> {
            if(deserialization.get(0).equals(each)) return;
            logger.debug("删除文件:" + each);
            new File(each).delete();
        });

        /* _12302_2021/5/9_< delete empty dir > */
        String sourceDir = output + File.separator + PropertyUtil.getProp("companySuffix") + File.separator  + PropertyUtil.getProp("moduleName");
        sourceDir = sourceDir.replaceAll("\\.", Matcher.quoteReplacement(File.separator));
        File dir = new File(sourceDir);
        logger.debug("==========================正在清除空目录...==========================");
        if(dir != null )recursionEmptyDir(dir);
    }

    /**
     * 递归删除空目录
     * @param file
     */
    private static void recursionEmptyDir(File file){
        if(file.list()!=null && file.list().length > 0){
            for (File listFile : file.listFiles()) { //service
                if (listFile.isDirectory()){
                    recursionEmptyDir(listFile);
                }
            }
            /* _12302_2021/5/9_< 检测自身 > */
            if(file.list().length==0) file.delete();
        }else {
            file.delete();
        }
    }
}
